var fs = require('fs');
var fsExtra = require('fs-extra');
var crypto = require('crypto');
var path = require('path');
var glob = require("glob");
var colors = require('colors');
var Promise = require('bluebird');

var taskPath = require('../path');
var request = require('./request');
var rulesCfg = require('./md5Rules');

var checkFiles = {
    _cdnVersion: null,
    _uploadCDNVersion: null,
    _fileMD5Map: {},
    _fileContentMap: {},
    _uploadMap: {},
    /**
     * 获取MD5码
     * @param str
     * @returns {*}
     */
    getMD5: function (str) {
        var md5 = crypto.createHash('md5');
        md5.update(str);
        return md5.digest('hex');
    },

    /**
     * 1、获取CDN版本号
     */
    getCDNVersion: function () {
        var cdn_url = `${taskPath.PATH_CDN}version.json?v=${new Date().getTime()}`;
        return new Promise((resolve, reject) => {
            request.requestFileUrl(cdn_url, (status, ret) => {
                if (status == 1) {
                    var versionCfg;
                    try {
                        versionCfg = JSON.parse(ret);
                        this._cdnVersion = versionCfg.version;
                        console.log(`【 1、CDN版本为：${this._cdnVersion ? this._cdnVersion : '暂无！！'} 】`.red);
                        resolve(versionCfg);
                    } catch (err) {
                        reject(err);
                    }
                } else {
                    reject(ret);
                }
            });
        });
    },

    // 获取md5Rules.js文件所配置的匹配规则，进行遍历生成文件对应的MD5信息
    getRulesFilesMD5: function () {
        var rootPath = path.resolve(__dirname, '../../');
        var projectPath = `${rootPath}/${taskPath.DIR_BUILD}`;

        var resPath;
        return new Promise((resolve, reject) => {
            var cdnRegularRules = rulesCfg.rules;
            cdnRegularRules.forEach((item, index) => {
                resPath = `${projectPath}/${item.src}`;
                // 遍历获取到的文件列表（包括目录）
                var fileList = glob.sync(resPath);
                if (fileList == null) {
                    reject();
                } else {
                    fileList.forEach((filepath) => {
                        var statInfo = fs.lstatSync(filepath);
                        if (!statInfo.isDirectory()) {
                            var content = fs.readFileSync(filepath, 'utf-8');
                            // MD5码
                            var md5 = this.getMD5(content);
                            // 扩展名
                            var extName = path.extname(filepath);
                            // 文件路径名（相对于projectPath）
                            var fileNamePath = filepath.replace(projectPath, "");
                            // console.log(`MD5码: ${md5} =扩展名：${extName}= ${fileNamePath} `);
                            this._fileMD5Map[fileNamePath] = {
                                'md5': md5,
                                'ext': extName,
                                'type': item.type
                            };
                            this._fileContentMap[fileNamePath] = content;
                        }
                    });
                }
            });
            console.log('【 2、本地规则匹配的文件的MD5配置：】'.red);
            console.log(this._fileMD5Map);
            resolve();
        });
    },

    cacheVersion: function () {
        return new Promise((resolve, reject) => {
            var rootPath = path.resolve(__dirname, '../../');
            var cacheJsonPath = `${rootPath}/versionCfg.json`;

            var isExist = fs.existsSync(cacheJsonPath);
            var content;
            if (!isExist) {
                content = JSON.stringify({});
                fs.writeFileSync(cacheJsonPath, {});
            } else {
                content = fs.readFileSync(cacheJsonPath, 'utf-8') || JSON.stringify({});
            }
            try {
                var cacheData = JSON.parse(content);
                var cdnVersion = this._cdnVersion;

                // 判断cdn版本是否存在
                if (cdnVersion) {
                    // 遍历本地规则文件的md5，与cdn的版本规则今夕对比
                    var cacheJsonMap = cacheData[cdnVersion];
                    console.log(`【 3、读取缓存CDN v${cdnVersion}的md5集：】`.red);
                    console.log(cacheJsonMap);
                    if (!cacheJsonMap) {
                        // cdn版本的缓存本地缺少，重写新版本
                        this._uploadMap = this._fileMD5Map;
                    } else {
                        // 遍历本地规则文件的md5，与cdn的版本规则今夕对比
                        var rulesJsonMap = this._fileMD5Map;
                        for (var key in rulesJsonMap) {
                            var item = rulesJsonMap[key];
                            // 如果缓存的json里面没有key这个或者md5不相等，那么久是新的
                            if (!cacheJsonMap[key] || cacheJsonMap[key].md5 != item.md5) {
                                console.log(`${item.md5} === ${key}  新文件`.green);
                                this._uploadMap[key] = item;
                            }
                        }
                    }

                    // 获取下一个版本后重写版本缓存
                    var newVersion = this.versionNum2Str(this.versionStr2Num(cdnVersion) + 1);
                    cacheData[newVersion] = this._fileMD5Map;
                    fs.writeFileSync(cacheJsonPath, JSON.stringify(cacheData));
                    this._uploadCDNVersion = newVersion;

                    console.log(`【 3.1、添加v${newVersion}本地缓存，更新CDN版本为${this._uploadCDNVersion}，重新缓存MD集 】`.red);
                    console.log(this._fileMD5Map);
                } else {
                    this._uploadMap = this._fileMD5Map;

                    // 获取最新版本后重写最新版本缓存
                    var newVersion = this.createNewestVersion(cacheData);
                    cacheData[newVersion] = this._fileMD5Map;
                    fs.writeFileSync(cacheJsonPath, JSON.stringify(cacheData));
                    this._uploadCDNVersion = newVersion;

                    console.log(`【 3、cdn版本获取失败，写入最新v${newVersion}的MD5缓存集 】`.red);
                    console.log(this._fileMD5Map);
                }
                console.log('【 4、本地与cdn配置比较后的文件集为：】'.red);
                console.log(this._uploadMap);
                resolve();
            } catch (err) {
                console.log("versionConfig.json解析出现异常：" + err);
                reject();
            }
        });
    },

    // 生成最新的版本号
    createNewestVersion: function (cacheData) {
        var defaultVersion = '1.0.00';
        if (cacheData == null || typeof cacheData != 'object')
            return defaultVersion;

        var versionArr = [];
        var verNum;
        for (var versionKey in cacheData) {
            if (cacheData.hasOwnProperty(versionKey)) {
                verNum = this.versionStr2Num(versionKey);
                versionArr.push(verNum);
            }
        }

        if (versionArr.length == 0)
            return defaultVersion;

        versionArr = versionArr.sort(function (a, b) {
            return b - a
        });

        var maxVerNum = versionArr[0];
        return this.versionNum2Str(maxVerNum + 1);
    },

    // 版本字符串转换成数字
    versionStr2Num: function (versionStr) {
        return parseInt(versionStr.split('.').join(''));
    },

    // 数字版本号转成字符串
    versionNum2Str: function (versionNum) {
        var one = Math.floor(versionNum / 1000);
        var two = Math.floor(versionNum / 100) % 10;
        var end = Math.floor(versionNum % 100);
        return `${one}.${two}.${end < 10 ? '0' + end : end}`
    },

    copyAndRenameFiles: function () {
        return new Promise((resolve, reject) => {
            var rootPath = path.resolve(__dirname, '../../');
            var projectPath = `${rootPath}/${taskPath.DIR_BUILD}`;

            // 移除upload目录
            fsExtra.removeSync(`${rootPath}/${taskPath.DIR_CDN_CONVERT}`);

            // copy all目录文件
            console.log('【 5、copy all目录文件 】'.red);
            for (var key in this._fileMD5Map) {
                var item = this._fileMD5Map[key];
                console.log(item);
                console.log(key);
                var fileName;
                var dist;
                if (item.type == 2) {
                    // 类型为2的先不创建文件
                    var keyArr = key.split('/');
                    var fullname = keyArr[keyArr.length - 1];
                    var name = fullname.replace(new RegExp(item.ext + '$'), '');
                    fileName = `${name}.${item.md5}${item.ext}`;
                } else {
                    fileName = `${item.md5}${item.ext}`;
                    dist = `${rootPath}/${taskPath.DIR_CDN_CONVERT_ALL}/${fileName}`;
                    //fs.writeFileSync(dist, this._fileContentMap[key]);
                    fsExtra.copySync(`${projectPath}${key}`, dist);
                }
            }

            // copy diff目录文件
            console.log('【 6、copy diff目录文件 】'.red);
            for (var key in this._uploadMap) {
                var item = this._uploadMap[key];

                if (item.type == 2)
                    continue;

                console.log(`${item.md5} === ${key}`.green);
                var fileName = `${item.md5}${item.ext}`;
                var dist = `${rootPath}/${taskPath.DIR_CDN_CONVERT_DIFF}/${fileName}`;
                //fs.writeFileSync(dist, this._fileContentMap[key]);
                fsExtra.copySync(`${projectPath}${key}`, dist);
            }

            // 写入版本到diff
            if (this._uploadCDNVersion) {
                var dist = `${rootPath}/${taskPath.DIR_CDN_CONVERT_DIFF}/version.json`;
                var versionData = {
                    version: this._uploadCDNVersion
                };
                fsExtra.outputFileSync(dist, JSON.stringify(versionData))
                console.log(`【 7、write diff目录版本文件 ${JSON.stringify(versionData)}】`.red);
            }
            resolve();
        });
    },

    combineCdnMD5Url: function () {
        return new Promise((resolve, reject) => {
            if (this._fileMD5Map == null)
                reject();
            else {
                var newFileMD5Map = {};
                for (var key in this._fileMD5Map) {
                    if (this._fileMD5Map.hasOwnProperty(key)) {
                        var item = this._fileMD5Map[key];
                        newFileMD5Map[key] = {
                            md5: item.md5,
                            ext: item.ext,
                            type: item.type || 1,
                            md5Url: `${taskPath.PATH_CDN}${item.md5}${item.ext}`
                        };

                    }
                }
                console.log(`【 7、处理完毕，resolve传递MD5集 】`.red);
                resolve(newFileMD5Map);
            }
        });
    },

    run: function (callback) {
        // Promise.all([
        //     this.getCDNVersion.call(this),
        //     this.getRulesFilesMD5.call(this),
        //     this.cacheVersion.call(this),
        //     this.printRet.call(this)
        // ]).catch((error) => {
        //     console.log("异常：" + error);
        // });
        this.getCDNVersion()
            .then(this.getRulesFilesMD5.bind(this))
            .then(this.cacheVersion.bind(this))
            .then(this.copyAndRenameFiles.bind(this))
            .then(this.combineCdnMD5Url.bind(this))
            .then((data, content) => {
                if (typeof callback == 'function') {
                    console.log(`【 8、传递MD5集给回调函数 】`.red);
                    callback(data);
                }
            })
            .catch((error) => {
                console.log("异常：" + error);
            });
    }
};
module.exports = checkFiles;
